package cn.edu.ctbu.sbadmin.common.core;


import cn.edu.ctbu.sbadmin.common.domain.MQueryParam;
import cn.edu.ctbu.sbadmin.common.domain.QObject;
import cn.edu.ctbu.sbadmin.common.domain.QueryAndItems;
import cn.edu.ctbu.sbadmin.common.domain.QueryPagePara;
import cn.edu.ctbu.sbadmin.common.utils.Helper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ClassUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import org.springframework.stereotype.Service;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;


/**
 * 基于通用MyBatis Mapper插件的Service接口的实现
 */
@Service
public abstract class AbstractService<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {


    @Autowired
    protected M baseMapper;

    @Override
    public M getBaseMapper() {
        return baseMapper;
    }

    protected Class<T> entityClass = currentModelClass();

    @Override
    public Class<T> getEntityClass() {
        return entityClass;
    }

//    protected Class<T> mapperClass = currentMapperClass();

//    @Override
//    protected Class<T> currentMapperClass() {
//        return (Class<T>) this.getResolvableType().as(AbstractService.class).getGeneric(0).getType();
//    }

    @Override
    protected Class<T> currentModelClass() {
        return (Class<T>) this.getResolvableType().as(AbstractService.class).getGeneric(1).getType();
    }

    /**
     * @see ResolvableType
     * @since 3.4.3
     */
    protected ResolvableType getResolvableType() {
        return ResolvableType.forClass(ClassUtils.getUserClass(getClass()));
    }


    @Override
    public List<T> findByAttrName(String AttName, Object value) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(AttName, value);
        return baseMapper.selectList(queryWrapper);

    }

    @Override
    public List<T>  getAll(){

        return baseMapper.selectList(null);

    }

    /**
     * 按属性查询，只返回一个
     *
     * @param AttName
     * @param value
     * @return
     */
    @Override
    public T findOneByAttrName(String AttName, Object value) {

        List<T> mylist = findByAttrName(AttName, value);
        if (mylist.size() > 0) {
            return mylist.get(0);
        } else {
            return null;
        }

    }


    @Override
    public Integer countByAttrName(String AttName, Object value) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(AttName, value);
        return baseMapper.selectCount(queryWrapper);

    }


    @Override
    public IPage<T> findByAttrNameTopN(String AttName, Object value, Integer n, String orderCol, Boolean asc) {

        Page<T> page = new Page<>(1, n);
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(AttName, value);
        if (asc) {
            queryWrapper.orderByAsc(orderCol);
        } else {
            queryWrapper.orderByDesc(orderCol);
        }

        IPage<T> userIPage = baseMapper.selectPage(page, queryWrapper);

        return userIPage;

    }


    @Override
    public IPage<T> getByPage(QueryPagePara mQuery) {
        QueryWrapper<T> example = new QueryWrapper<>();

        Integer currentPage = 1;

        Integer pageSize = 9999;//默认取相当大的值


        currentPage = mQuery.getOffset();
        pageSize = mQuery.getLimit();

        List<QueryAndItems> Pares = mQuery.getWherePara();  //获取4元组参数列表


        for (QueryAndItems items : Pares) {
            //现阶段只处理了and项，其它的还没有处理

            for (MQueryParam item : items.getQueryList()) {
                String op = item.getAction().replace(" ", "").toLowerCase();
                String P = item.getKey();


                Object V1 = item.getValue1();
                Object V2 = item.getValue2();

                switch (op) {
                    case "=":
                        example.eq(P, V1);
                        break;
                    case "<":
                        example.lt(P, V1);
                        break;
                    case ">":
                        example.gt(P, V1);
                        break;
                    case "<=":
                        example.le(P, V1);
                        break;
                    case "=<":
                        example.le(P, V1);
                        break;
                    case ">=":
                        example.ge(P, V1);
                        break;
                    case "=>":
                        example.ge(P, V1);
                        break;
                    case "like":
                        example.like(P, "%" + V1 + "%");
                        break;
                    case "between":

                        String S1 = V1.toString();
                        String S2 = V2.toString();

                        if (!StringUtils.isAllBlank(S1) && (!StringUtils.isAllBlank(S2))) {
                            example.between(P, S1, S2);
                        }


                        break;

                    default:
                        example.eq(P, V1);

                }

            }
            //end of items


        }

        Page<T> page = new Page<>(currentPage, pageSize);
        IPage<T> userIPage = baseMapper.selectPage(page, example);

        return userIPage;
    }

    /**
     * 键值对支持查询
     * @param map
     * @return
     */
    @Override
    public IPage<T>  list(Map<String, Object> map){
        QueryWrapper<T> example = new QueryWrapper<>();

        Integer currentPage = 1;

        Integer pageSize = 9999;//默认取相当大的值

        for (Map.Entry<String, Object> entry : map.entrySet()) {
            //System.out.println("key值："+entry.getKey()+" value值："+entry.getValue());
            String key = entry.getKey();
            Object value = entry.getValue();
            if (!key.equals("offset") && !key.equals("limit")) {
                //不是关键字
                example.eq(key, value);
            }
        }

        if (map.containsKey("offset") && map.containsKey(("limit"))) {
            currentPage = Integer.parseInt(map.get("offset").toString());
            pageSize = Integer.parseInt(map.get("limit").toString());
        }

        Page<T> page = new Page<>(currentPage, pageSize);
        IPage<T> userIPage = baseMapper.selectPage(page, example);

        return userIPage;


    }


    @Override
    public IPage<T> getPageByObject(QObject<T> queryObj) {
        T mydata = queryObj.getData();
        Boolean sortDirect = queryObj.getDirect();
        String sortName = queryObj.getSort();
        //  mydata,Integer currentPage,Integer pageSize,String sortName,boolean sortDirect
        Class<?> aClass = mydata.getClass();
        QueryWrapper<T> example = new QueryWrapper<>();
        // 获取对象属性
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            if (fieldName.equalsIgnoreCase("SerialVersionUID")) {
                continue;
            }

            String fieldType = field.getType().getSimpleName();
            String colName = Helper.camelToUnderline(fieldName);//反驼峰转换

            try {
                //获取get方法获取属性值 传入属性名称
                PropertyDescriptor pd = new PropertyDescriptor(fieldName, aClass);
                Method rm = pd.getReadMethod();
                // 这块一定要传入t 而不是 t.getClass().newInstance()
                Object myvalue = rm.invoke(mydata);
                if (myvalue != null) {

                    //针对非空才处理
                    if (fieldType.equalsIgnoreCase("string")) {
                        String strValue = myvalue.toString();
                        if (com.baomidou.mybatisplus.core.toolkit.StringUtils.isNotBlank(strValue)) {
                            strValue = com.baomidou.mybatisplus.core.toolkit.StringUtils.toStringTrim(strValue);

                            example.like(colName, "%" + strValue + "%");
                        }


                    } else {
                        example.eq(colName, myvalue);
                    }
                }

            } catch (Exception e) {

            }

        }
        if (sortName != null) {
            example.orderBy(true, sortDirect, sortName);
        }


        Page<T> page = new Page<>(queryObj.getPageNum(), queryObj.getPageSize());
        IPage<T> userIPage = baseMapper.selectPage(page, example);

        return userIPage;
    }

    @Override
    public Map<String, Object> getByPage(QueryPagePara request, T entity) {
        return null;
    }

    @Override
    public Map<String, Object> selectByPageNumSize(QueryPagePara request, Supplier<?> s) {
        return null;
    }


    @Override
    public int removeByIds(Long[] ids) {
        List<Long> longList = Arrays.asList(ids);

        return removeByIds(longList) ? 1 : 0;
    }

    @Override
    public int removeByIds(Integer[] ids) {

        List<Integer> longList = Arrays.asList(ids);
        return removeByIds(longList) ? 1 : 0;
    }

    @Override
    public List<T> getByIds(long[] ids) {

        List<T> models = new ArrayList<T>();

        for (Long id :
                ids) {
            T newItem = getById(id);
            models.add(newItem);

        }
        return models;


    }
}
